<?php

declare(strict_types=1);

namespace Zyucv7\Components\AI\LLM;

use Zyucv7\Components\Http\Client as HttpClient;
use Zyucv7\Components\AI\LLM\Exceptions\ClientException as LLMClientException;

/**
 * 通用的LLM API 父类
 */
abstract class Client
{

    protected string $apiKey; // API Key
    protected string $baseUrl; // API 公用地址
    protected string $sendUrl; // API 发送地址
    protected string $model; // 模型名称
    protected HttpClient $client; // HTTP 客户端
    protected string $systemPrompt; // 系统提示语
    protected string $jsonStr = ''; // 发送的原始JSON字符串
    protected string $userPrompt; // 用户提示语

    public function __construct()
    {
        if (!$this->apiKey || !$this->baseUrl) {
            throw LLMClientException::InvalidArgument('API Key or Base URL is not set.');
        }

        $this->client = new HttpClient($this->baseUrl, [
            'json_raw' => true, // 返回原始数据
        ]);
        $this->client->addHeader('Authorization', 'Bearer ' . $this->apiKey);
        $this->client->addHeader('Content-Type', 'application/json');
    }

    /**
     * 设置模型
     * @param string $model 模型名称
     */
    public function setModel(string $model)
    {
        $this->model = $model;
    }

    /**
     * 设置发送地址
     * @return string $url
     */
    public function setSendUrl(string $url): self
    {
        $this->sendUrl = $url;
        return $this;
    }

    /**
     * 设置系统提示语
     * @param string $prompt 提示语
     */
    public function setSystemPrompt(string $prompt): self
    {
        $this->systemPrompt = $prompt;
        return $this;
    }

    /**
     * 设置用户提示语
     * @param string $prompt 提示语
     */
    public function setUserPrompt(string $prompt): self
    {
        $this->userPrompt = $prompt;
        return $this;
    }

    protected abstract function buildOptions(): void; // 构建选项

    // 发送请求
    public function send(): array
    {
        $this->buildOptions();
        if (!$this->jsonStr) {
            throw LLMClientException::InvalidArgument('JSON string is not set.');
        }
        $this->client->post($this->sendUrl, $this->jsonStr);
        $data = $this->client->getData();
        $choices = $data['choices'] ?? [];
        if (count($choices) === 0) {
            throw LLMClientException::InvalidArgument('No choices are returned.');
        }
        if(!isset($choices[0]['message']['content'])) {
            throw LLMClientException::InvalidArgument('No message content is returned.');
        }
        $respData = json_decode($choices[0]['message']['content'], true);
        if(isset($data['request_id'])) {
            $respData['request_id'] = $data['request_id'];
        }
        if(isset($data['id'])) {
            $respData['id'] = $data['id'];
        }
        return $respData;
    }
}
